package tokenservice

import (
	"context"
	"fmt"
	"gitee.com/go-mid/booter/bootservice"
	"gitee.com/go-mid/infra/xlog"
	"github.com/dgrijalva/jwt-go"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"time"
)

var DefaultTokenService = &TokenServiceImpl{}

func (m *TokenServiceImpl) Init() error {
	fun := "TokenServiceImpl.Init -->"
	var ctx = context.Background()
	xlog.Infof(ctx, "%s  start", fun)
	xlog.Infof(ctx, "%s  start", fun)
	m.initJob(ctx)
	xlog.Infof(ctx, "%s  end", fun)
	return nil
}
func (m *TokenServiceImpl) Driver() (string, interface{}) {
	return "", &bootservice.EmptyServer{}
}
func (m *TokenServiceImpl) initJob(ctx context.Context) {
}

type IssuerConfig struct {
	ExpireSecond int64
	Key          string
}

var IssuerConfigMap = map[string]IssuerConfig{
	"xingyuAtk": {
		ExpireSecond: 10 * 24 * 3600,
		Key:          "d80fc1424435adccc5cdf15589bdc158054afa1cbf116983ad12a8e73289e7c0",
	},
	"xingyuRtk": {
		ExpireSecond: 30 * 24 * 3600,
		Key:          "fb7f9c73586f85a861226f3d76ee1eb1d185ff4b6cef2a901d29a071c3e2de0d",
	},
}

type TokenServiceImpl struct{}

type PayloadClaims struct {
	Payload string `json:"payload"`
	jwt.StandardClaims
}
type GetTokenReq struct {
	//颁布者
	Issuer string `json:"issuer"`
	//信息
	Payload string `json:"payload"`
}
type GetTokenRes struct {
	Token  string `json:"token"`
	Expire int64  `json:"expire"`
}

func (m *TokenServiceImpl) GetToken(ctx context.Context, req *GetTokenReq) (*GetTokenRes, error) {
	fun := "TokenServiceImpl.GetToken -->"
	nowTime := time.Now()
	issConf, ok := IssuerConfigMap[req.Issuer]
	if !ok {
		xlog.Infof(ctx, "%s illegal issuer: req: %v", fun, req)
		return nil, status.Error(codes.PermissionDenied, fmt.Errorf("illegal issuer: %s", req.Issuer).Error())
	}
	expireTime := nowTime.Add(time.Duration(issConf.ExpireSecond) * time.Second)
	issuer := req.Issuer

	claims := PayloadClaims{
		Payload: req.Payload,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    issuer,
			IssuedAt:  nowTime.Unix(),
		},
	}
	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(issConf.Key))
	if err != nil {
		xlog.Infof(ctx, "%s create token error : req: %v, err: %v", fun, req, err)
		return nil, status.Error(codes.PermissionDenied, err.Error())
	}
	return &GetTokenRes{
		Token:  token,
		Expire: expireTime.Unix(),
	}, nil
}

type VerifyTokenReq struct {
	//颁布者
	Issuer string `json:"issuer"`
	Token  string `json:"token"`
}
type VerifyTokenRes struct {
	IsValid bool   `json:"is_valid"`
	Payload string `json:"payload"`
}

func (m *TokenServiceImpl) VerifyToken(ctx context.Context, req *VerifyTokenReq) (*VerifyTokenRes, error) {
	fun := "TokenServiceImpl.VerifyToken -->"
	issConf, ok := IssuerConfigMap[req.Issuer]
	if !ok {
		xlog.Infof(ctx, "%s illegal issuer: req: %v", fun, req)
		return nil, status.Error(codes.PermissionDenied, fmt.Errorf("illegal issuer: %s", req.Issuer).Error())
	}

	tokenClaims, err := jwt.ParseWithClaims(req.Token, &PayloadClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(issConf.Key), nil
	})
	if err != nil {
		xlog.Infof(ctx, "%s ParseWithClaims err: req: %v, err: %v", fun, req, err)
		return nil, status.Error(codes.PermissionDenied, err.Error())
	}

	if tokenClaims == nil {
		xlog.Infof(ctx, "%s ParseWithClaims fail: req: %v ", fun, req)
		return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("token parse fail"))
	}
	claims, ok := tokenClaims.Claims.(*PayloadClaims)
	if !ok {
		xlog.Infof(ctx, "%s token valid fail: req: %v ", fun, req)
		return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("illegal token"))
	}
	isValid := tokenClaims.Valid
	if !isValid {
		xlog.Infof(ctx, "%s token valid fail: req: %v ", fun, req)
	}
	return &VerifyTokenRes{
		IsValid: isValid,
		Payload: claims.Payload,
	}, nil
}
